"""
Metrics storage service

Provides unified interface for saving and querying device metrics
"""

from __future__ import annotations

import logging
from datetime import datetime
from typing import Any

from sqlalchemy.ext.asyncio import AsyncSession

from app.db.database_adapter import get_timeseries_adapter


logger = logging.getLogger(__name__)


class MetricsService:
    """
    Metrics storage service

    Responsibilities:
    - Save device metrics to time-series database
    - Query historical metric data
    - Aggregate statistics
    """

    @staticmethod
    async def save_metric(
        db: AsyncSession,
        device_id: int,
        metric_name: str,
        value: float,
        timestamp: datetime,
        quality: str = "good",
        unit: str | None = None
    ) -> bool:
        """
        Save a single metric

        Args:
            db: Database session
            device_id: Device ID
            metric_name: Metric name
            value: Metric value
            timestamp: Timestamp
            quality: Data quality (good/bad/uncertain)
            unit: Unit of measurement

        Returns:
            bool: True if save succeeded

        Raises:
            Exception: If save fails
        """
        try:
            adapter = get_timeseries_adapter()

            result = await adapter.save_metric(
                db=db,
                device_id=device_id,
                metric_name=metric_name,
                value=value,
                timestamp=timestamp,
                quality=quality,
                unit=unit
            )

            logger.info(
                f"Metric saved: device_id={device_id}, "
                f"metric={metric_name}, value={value}"
            )

            return result

        except Exception as e:
            logger.error(f"Failed to save metric: {e}")
            raise

    @staticmethod
    async def save_metrics_batch(
        db: AsyncSession,
        device_id: int,
        metrics: list[dict[str, Any]]
    ) -> int:
        """
        Batch save metrics

        Args:
            db: Database session
            device_id: Device ID
            metrics: List of metrics [{"name": "temp", "value": 25.5, "timestamp": ...}, ...]

        Returns:
            int: Number of successfully saved metrics
        """
        adapter = get_timeseries_adapter()
        success_count = 0

        for metric in metrics:
            try:
                await adapter.save_metric(
                    db=db,
                    device_id=device_id,
                    metric_name=metric["name"],
                    value=metric["value"],
                    timestamp=metric["timestamp"],
                    quality=metric.get("quality", "good"),
                    unit=metric.get("unit")
                )
                success_count += 1
            except Exception as e:
                logger.error(f"Failed to save metric {metric['name']}: {e}")

        logger.info(
            f"Batch save completed: {success_count}/{len(metrics)} metrics saved"
        )

        return success_count

    @staticmethod
    async def query_metrics(
        db: AsyncSession,
        device_id: int,
        metric_name: str,
        start_time: datetime,
        end_time: datetime,
        **kwargs: Any
    ) -> list[dict[str, Any]]:
        """
        Query metric data

        Args:
            db: Database session
            device_id: Device ID
            metric_name: Metric name
            start_time: Start time
            end_time: End time
            **kwargs: Additional parameters (interval, etc.)

        Returns:
            List[Dict]: List of metric data
        """
        adapter = get_timeseries_adapter()

        results = await adapter.query_metrics(
            db=db,
            device_id=device_id,
            metric_name=metric_name,
            start_time=start_time,
            end_time=end_time,
            **kwargs
        )

        logger.info(
            f"Query completed: device_id={device_id}, "
            f"metric={metric_name}, results={len(results)}"
        )

        return results
